﻿using System.Collections.Generic;
using BlogsAPI.Interfaces;

namespace BlogsAPI.Sites
{
    using System.Web;
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Net;
    using System.Text;
    using System.Text.RegularExpressions;
    using Abstract;

    /// <summary>
    /// Статистика страницы
    /// </summary>
    public struct OKStats
    {
        /// <summary>
        /// Is Page 
        /// </summary>
        public bool IsPage;
        /// <summary>
        /// Общее число лайков на странице
        /// </summary>
        public int LikesTotal;
        /// <summary>
        /// Число участников
        /// </summary>
        public int Members;
        /// <summary>
        /// Число постов
        /// </summary>
        public int Topics;
        /// <summary>
        /// Имя страницы
        /// </summary>
        public string Name;
        /// <summary>
        /// Описание страницы
        /// </summary>
        public string Description;
        /// <summary>
        /// Являются ли официальной
        /// </summary>
        public bool IsVerified;
        /// <summary>
        /// Являются ли закрытой
        /// </summary>
        public bool IsPrivate;
        /// <summary>
        /// Ссылки на некоторых друзей, с целью дальнейшего их обновления
        /// UserId - UserName
        /// </summary>
        public Dictionary<string,string> SomeFriends;

    }

    /// <summary>
    /// Русскоязычный клон <see cref="Facebook"/> - http://ok.ru
    /// </summary>
    /// <remarks>Renamed Odnoklassniki to Odnoklassnik to have shorten name</remarks>
    [BlogServiceAPI(Description = "Odnoklassniki.ru", Link = "http://odnoklassniki.ru")]
    public class Odnoklassnik : BlogServer, ILike
    {
        #region Regexes

        private static readonly Regex Validation = new Regex(@"^https?://(?:[-_\w]+\.)?(?:odnoklassniki\.ru|ok\.ru)", Regexoptions);
        private static readonly Regex ValidationFull = new Regex(@"^https?://(?:[-_\w]+\.)?(?:odnoklassniki\.ru|ok\.ru)/(?:profile/|group/)?([^/]+)(?:/|$)", Regexoptions);

        private readonly static Regex rAvatar = new Regex(@"<img[^>]+class\W+feed_ava[^>]+src\W+([^""']+)\W[^>]+48\W", Regexoptions);
        private readonly static Regex rDescription = new Regex(@"<div[^>]+?id\W+aboutGroup.*?<span[^>]+>([^<]+)+<", Regexoptions);
        private readonly static Regex rName = new Regex(@"<span[^>]+_name_[^>]+>(?:<div[^>]+></div>)?([^<]+)<", Regexoptions);
        //
        private readonly static Regex rMembers = new Regex(@"(?:Members|Friends)[^<]+<span[^>]+>((?:\d|&nbsp;|\s)+)<", Regexoptions);
        private readonly static Regex rTopics = new Regex(@"Topics[^<]+<span[^>]+>((?:\d|&nbsp;|\s)+)<", Regexoptions);
        //_klass[^>]+>\D+((?:\d|&nbsp;)+)\D
        private readonly static Regex rKlass = new Regex(@"<span[^>]+js-count[^>]+>((?:\d|&nbsp;)+)<", Regexoptions);
        //friends 
        private readonly static Regex rFriendsUser = new Regex(@"itemprop\W+name[^>]+?href\W+(?<type>profile/|group/)?(\w+)[^>]+>([^<]+)<", Regexoptions);
        private readonly static Regex rFriendsGroup = new Regex(@"title\W+(\w+)\W[^>]+?itemprop\W+url[^>]+?href\W+(?<type>profile/|group/)?(\w+)[^>]+>", Regexoptions);
        #endregion

        #region interface: BlogServer

        [DebuggerStepThrough]
        public Odnoklassnik()
        {
            Encoding = Encoding.UTF8;
        }

        /// <summary>
        /// http://www.t30p.ru/Odnoklassniki.aspx
        /// </summary>
        public override bool HasRating
        {
            get { return true; }
        }

        /// <summary>
        /// проверка, является ли передаваемый урл чатью этого сервиса
        /// </summary>
        public override Boolean ValidateLink(String sLink)
        {
            return Validation.Match(sLink).Success;
        }

        /// <summary>
        /// проверка, является ли передаваемый урл чатью этого сервиса
        /// </summary>
        /// <param name="sLink">ссылка для проверки</param>
        /// <param name="userName">Имя пользователя на блогохостинге</param>
        /// <param name="bType">Тип блога - пользователь или сообщество</param>
        public override Boolean ValidateLink(String sLink, out String userName, out BlogType bType)
        {
            //http://www.odnoklassniki.ru/profile/535419758271/
            //http://odnoklassniki.ru/ekaterina.nagorneva
            bType = BlogType.Unknown;
            Match m = ValidationFull.Match(sLink);
            if (m.Success)
            {
                bType = sLink.Contains("group/")?BlogType.Community : BlogType.User;
                if(String.Compare(m.Groups[1].Value,"live",true) != 0 &&
                    String.Compare(m.Groups[1].Value, "video", true) != 0                    )
                {
                    //прямые трансляции и видео
                    userName = m.Groups[1].Value;
                }else
                {
                    //http://ok.ru/live/123123123
                    userName = String.Empty;
                }
            }
            else
            {
                userName = String.Empty;
            }
            return m.Success;
        }

        /// <summary>
        /// Получение ссылки на блог блогера
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="btype">Тип блога - пользователь или сообщество</param>
        public override String GetBlogLink(string userName, BlogType btype)
        {
            if (userName == "ok.ru") return "http://ok.ru";//
            return String.Format("http://ok.ru/{0}{1}", Regex.Match(userName, @"^\d+$").Success ?
                (btype==BlogType.Community?"group/":"profile/") :"" ,userName);
        }
       
        /// <summary>
        /// Получение аватарки по имени
        /// </summary>
        /// <param name="userName">имя блогера</param>
        /// <param name="bt">reserved</param>
        /// <returns></returns>
        public override string ExtractAvatar(string userName, BlogType bt)
        {
            string sRet = String.Empty;
            try
            {
                string blogname = GetBlogLink(userName, bt);
                HttpWebRequest myHttpWebRequest = MakeRequest(blogname);
                myHttpWebRequest.Method = "GET"; // метод GET
                myHttpWebRequest.Referer = blogname;
                var myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding.UTF8).ReadToEnd();
                myHttpWebResponse.Close();
                //
                Match mc = rAvatar.Match(result);
                if (mc.Success)
                {
                    sRet = Common.FixHttp(HttpUtility.HtmlDecode(mc.Groups[1].Value));
                }
            }
            catch (Exception e1)
            {
                Debug.WriteLine(e1.Message);
            }
            return sRet;
        }

        #endregion

        #region ILike

        public Dictionary<string, int> GetLikes(Uri Link)
        {
            var oRet = new Dictionary<string, int>();
            try
            {
                HttpWebRequest myHttpWebRequest;
                HttpWebResponse myHttpWebResponse;
                string faceLink = String.Format(
                        "http://ok.ru/dk?st.cmd=extLike&uid=odklcnt0&ref={0}",
                        HttpUtility.UrlEncode(Link.OriginalString));
                myHttpWebRequest = MakeRequest(faceLink);
                myHttpWebRequest.Method = "GET"; // метод GET
                myHttpWebRequest.Referer = "http://ok.ru";
                //получаем ответ и его разбираем...
                myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding.UTF8).ReadToEnd();
                myHttpWebResponse.Close();
                Match mc = Regex.Match(result, @",'(\d+)'", RegexOptions.IgnoreCase | RegexOptions.Singleline);
                if(mc.Success)
                {
                    oRet.Add("shares", int.Parse(mc.Groups[1].Value));
                }
            }
            catch (Exception e1)
            {
                Debug.WriteLine(e1);
            }
            return oRet;
        }

        #endregion

        /// <summary>
        /// Получение статистики по одной страницы путем ручного парсинга
        /// </summary>
        /// <param name="userName">имя пользователя из ссылки</param>
        /// <returns>данные по странице</returns>
        public OKStats GetPageStats(string userName)
        {
            var ps = new OKStats();
            ps.SomeFriends = new Dictionary<string, string>(0);
            try
            {
                long id;
                ps.IsPage = !long.TryParse(userName, out id);

                string blogname = GetBlogLink(userName);
                HttpWebRequest myHttpWebRequest = MakeRequest(blogname);
                myHttpWebRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
                myHttpWebRequest.Method = "GET"; // метод GET
                myHttpWebRequest.Referer = blogname;
                var myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                string result = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding.UTF8).ReadToEnd();
                myHttpWebResponse.Close();
                //
                var m = rName.Match(result);
                if (m.Success)
                {
                    ps.Name = HttpUtility.HtmlDecode(m.Groups[1].Value);
                }
                ps.IsVerified = result.Contains("<div title=\"Official page\"");
                ps.IsPrivate = result.Contains("\"private group\"");
                //
                m = rMembers.Match(result);
                if (m.Success)
                {
                    ps.Members = int.Parse(m.Groups[1].Value.Replace("&nbsp;", "").Replace(" ", ""));
                }
                if (!ps.IsPrivate)
                {
                    //
                    m = rDescription.Match(result);
                    if (m.Success)
                    {
                        ps.Description = HttpUtility.HtmlDecode(m.Groups[1].Value);
                    }
                    //
                    if (ps.IsPage)
                    {
                        //
                        m = rTopics.Match(result);
                        if (m.Success)
                        {
                            ps.Topics = int.Parse(m.Groups[1].Value.Replace("&nbsp;", "").Replace(" ", ""));
                        }

                        //likes per page
                        MatchCollection mc = rKlass.Matches(result);
                        foreach (Match match in mc)
                        {
                            ps.LikesTotal += int.Parse(match.Groups[1].Value.Replace("&nbsp;", "").Replace(" ", ""));
                        }
                        //
                        mc = rFriendsGroup.Matches(result);
                        foreach (Match match in mc)
                        {
                            string userid = Common.DelHttp(GetBlogLink(match.Groups[2].Value, match.Groups["type"].Value.Contains("group") ? BlogType.Community : BlogType.User));
                            if (System.String.Compare(userid, userName, System.StringComparison.OrdinalIgnoreCase) != 0)
                            {
                                ps.SomeFriends.Add(userid, match.Groups[1].Value);
                            }
                        }
                    }
                    else
                    {
                        MatchCollection mc = rFriendsUser.Matches(result);
                        foreach (Match match in mc)
                        {
                            string userid = Common.DelHttp(GetBlogLink(match.Groups[1].Value, match.Groups["type"].Value.Contains("group") ? BlogType.Community : BlogType.User));
                            if (System.String.Compare(userid, userName, System.StringComparison.OrdinalIgnoreCase) != 0)
                            {
                                ps.SomeFriends.Add(userid, match.Groups[2].Value);
                            }
                        }
                    }
                }
            }
            catch (Exception e1)
            {
                Debug.WriteLine("Ошибка загрузки статистики: " + e1.Message);
            }
            return ps;
        }
    }
}